package ua.at.javac.server;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import ua.at.javac.cron.JournalRow;
import com.google.appengine.api.rdbms.AppEngineDriver;

/**
 * Реализация коннектора к SQL базе данных
 * @author CHerry
 * @serial 101
 * @since  Nov 14, 2011
 */
public class Database {
	private static Connection conn = null;
	
	public Database() throws ClassNotFoundException {
		try {
			DriverManager.registerDriver(new AppEngineDriver());
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Error: AppEngineDriver JDBC not register.");
		}
		System.out.println("AppEngineDriver loading success.");
	}

	//Вызывается для соединения с базой данных
	private void getConnection () {
	System.out.println(
			"Wait connection to... jdbc:google:rdbms://vladcherry:forecast/...");
	

	String pathConnection = 
			"jdbc:google:rdbms://vladcherry:forecast/weather";
	String nameConnection = "root";
	String passConnection = "";
	
	try {
		conn = DriverManager.getConnection(pathConnection,
				nameConnection, passConnection);		
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
		System.out.println("Error connection to"+ pathConnection);
	}
	System.out.println("Connection OK >");
	}
   
/**
	Adds a log table settings forecast for the period
	(Добавляет данные в журнал погоды) 
	@param upToDate дата когда ожидается вводимая (погода в формате 2011-12-31)
	@param site_id код сайта и города из таблицы site
	@param period_id код на какой период дня (1-утро,2-день,3-вечер,4-ночь)
	@param cloudiness облачность (%)
	@param temperature температура (град.цельсия)
	@param precipitation осадки (мм)
	@param humidity влажность (%)
	@param pressure давление (мм.ртутного столба)
	@param windSpeed скорость ветра (м/с)
	@param wind_id код напраления ветра (1-N,2-NE,3-E,4-SE,5-S,6-SW,7-W,8-NW)
	@param forecast_day за сколько дней спрогнозирована эта погода (1, 2, 3, 4, 5, 6, 7 ...)
	*/
	public void addToJournal(   String  upToDate, 
								int	 site_id,
								int	 period_id,
								int	 cloudiness, 
								int	 temperature,
								double  precipitation,
								int	 humidity,
								int	 pressure,
								int	 windSpeed,
								int	 wind_id,
								int	 forecast_day){
		getConnection ();
		PreparedStatement pstmt;
		try {
			pstmt = conn.prepareStatement(
					"INSERT INTO journal " +
					"( uptodate," +
					" site_id," +
					" period_id," +
					" cloudiness," +
					" temperature," +
					" precipitation," +
					" humidity," +
					" pressure," +
					" windSpeed," +
					" wind_id," +
					" forecast_day)" +
					"VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? , ?);");
	
		pstmt.setString (1, upToDate);
		pstmt.setInt	(2, site_id);
		pstmt.setInt	(3, period_id);
		pstmt.setInt	(4, cloudiness);
		pstmt.setInt	(5, temperature);
		pstmt.setDouble (6, precipitation);
		pstmt.setInt	(7, humidity);
		pstmt.setInt	(8, pressure);
		pstmt.setInt	(9, windSpeed);
		pstmt.setInt	(10,wind_id);
		pstmt.setInt	(11,forecast_day);
	
		pstmt.addBatch();
		conn.setAutoCommit(false);
		pstmt.executeBatch();
		conn.setAutoCommit(true);
		pstmt.close();
		conn.close();
		
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	public int addToJournalList (List<JournalRow> jRow){   
		getConnection();
		
		// готовим заголовок запроса для добавления строк
		String sqlQuery="INSERT INTO journal "+
				"(uptodate," + 
				" site_id," +
				" period_id," +
				" cloudiness," +
				" temperature," +
				" precipitation," +
				" humidity," +
				" pressure," +
				" windSpeed," +
				" wind_id," +
				" forecast_day ) VALUES ";
		for (JournalRow row : jRow ){
			sqlQuery = sqlQuery+ "(" + row.getText() + "),";
		}
		
		sqlQuery = sqlQuery.substring(0, sqlQuery.length() - 1) + ";";
		//System.out.println(sqlQuery);
		Statement stmt;
		
		int count = 0;
		try {
			stmt = conn.createStatement();
			count = stmt.executeUpdate(sqlQuery);
		
		System.out.println("Add: "+count+" rows.");
		
		stmt.close();
		conn.close();
		
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return count;
		}

	/**
	 * Добавляет данные в журнал фактической погоды 
	@param upToDate дата погоды в формате 2011-12-31
	@param period_id код на какой период дня 
	(1-утро,2-день,3-вечер,4-ночь)
	@param cloudiness облачность (%)
	@param temperature температура (град.цельсия)
	@param precipitation осадки (мм)
	@param humidity влажность (%)
	@param pressure давление (мм.ртутного столба)
	@param windSpeed скорость ветра (м/с)
	@param wind_id код напраления ветра 
	(1-N,2-NE,3-E,4-SE,5-S,6-SW,7-W,8-NW)
	@param forecast_day за сколько дней спрогнозирована эта погода
	 *
	 */
	public void addToForecast(  String  upToDate, 
			int	 period_id,
			int	 cloudiness, 
			int	 temperature,
			double  precipitation,
			int	 humidity,
			int	 pressure,
			int	 windSpeed,
			int	 wind_id){
		getConnection ();
		PreparedStatement pstmt;
		try {
			pstmt = conn.prepareStatement(
					"INSERT INTO forecast " +
							"( uptodate," +
							" period_id," +
							" cloudiness," +
							" temperature," +
							" precipitation," +
							" humidity," +
							" pressure," +
							" windSpeed," +
							" wind_id)" +
					"VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?);");
		
		pstmt.setString (1, upToDate);
		pstmt.setInt	(2, period_id);
		pstmt.setInt	(3, cloudiness);
		pstmt.setInt	(4, temperature);
		pstmt.setDouble (5, precipitation);
		pstmt.setInt	(6, humidity);
		pstmt.setInt	(7, pressure);
		pstmt.setInt	(8, windSpeed);
		pstmt.setInt	(9,wind_id);
		
		pstmt.addBatch();
		conn.setAutoCommit(false);
		pstmt.executeBatch();
		conn.setAutoCommit(true);
		pstmt.close();
		conn.close();

		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/** 
		Prints to the console specified table
		(Печатает в консоль указанную таблицу)
		@param table -name
		<BR><var>(имя таблицы)</var>
		@param column -number of columns 
		<BR><var>(количество столбцов в таблице)</var>
	 */
	public void printToConsole(String table, int column) {
		getConnection ();
		Statement stmt;
		try {
			stmt = conn.createStatement();
	
		String sqlQuery = "SELECT * FROM ";
		sqlQuery=sqlQuery.concat(table);
		System.out.println(sqlQuery);
		ResultSet rs = stmt.executeQuery(sqlQuery);
		System.out.println("Table name: "+table);
		while (rs.next()) {
			System.out.print(rs.getRow() + ".|");
			
			for (int i = 1; i <= column; i++){
				System.out.print("\t" + rs.getString(i)+"\t"+"|");
			}
			System.out.println();
		}
		stmt.close();
		conn.close();
	
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	/**
	 * Печать в консоль 
	 * журнала погоды подставляя значения из справочных таблиц
	 */
	public void printLinkJournal() {
		printSqlQuery("SELECT * FROM linkJournal", 11); 
	}
	/**
	 * Печать в консоль 
	 * журнала погоды подставляя значения из справочных таблиц
	 * @param upToDate дата погоды в формате: "2012-12-31"
	 */
	public void printLinkJournal(String upToDate) {
		printTable("linkJournal", upToDate, 11);
	}
	
	/**
	 * Печать в консоль журнала погоды
	 */
	public void printJournal() {
		printSqlQuery("SELECT * FROM journal", 11); 
	}
	/**
	 * Печать в консоль журнала погоды
	 * @param upToDate дата погоды в формате: "2012-12-31"
	 */
	public void printJournal(String upToDate) {
		printTable("journal", upToDate, 11);
	}
	/**
	 * Печать в консоль таблицы с фильтрацией по дате
	 * @param table имя таблицы
	 * @param upToDate дата в формате: "2012-12-31"
	 * @param row количество столбцов
	 */
	private void printTable(String table, String upToDate, int row) {
		String sqlQuery="SELECT * FROM "+table+" WHERE (uptodate='" +
						upToDate + "')";
		printSqlQuery(sqlQuery, row); 
	}
	
	/**
	 * Печать в консоль фактической погоды
	 */
	public void printForecast() {
		printSqlQuery("SELECT * FROM forecast", 9);
	}
	/**
	 * Печать в консоль фактической погоды
	 * @param upToDate дата фактической погоды в формате: "2012-12-31"
	 */
	public void printForecast(String upToDate) {
		printTable("forecast", upToDate, 9);
	}
	
	
	/**
	* Print to console information Tables : 
	  * <LI> Periods Weather (morning, afternoon, evening, night)
	  * <LI> The wind rose,
	  * <LI> The sites and cities.
	  * <BR><BR> ( Печать в консоль справочных таблиц : 
	  * <LI> Периодов прогноза погоды (утро,день,вечер,ночь),
	 *  <LI> Розы ветров,
	 *  <LI> Сайтов и городов.
	 */
	public void printDictonary() {
		printToConsole("period",3);
		printToConsole("wind",2);
		printSqlQuery(
				"SELECT site.site_id," +
						" city.city_id," +
						" city.city," +
						" site.http," +
						" site.site_name " +
						"FROM city " +
						"INNER JOIN site " +
						"ON (city.city_id = site.city)", 5);
	}
	
	/**
	 * 
	 * @param sqlQuery - SQL Query in the database 
	 * <BR><var>(SQL запрос на выборку данных из базы данных)
	 * @param column - Number of columns in table 
	 * <BR><var>(количество колонок в таблице)
	 */
	public void printSqlQuery(String sqlQuery, int column) {
		getConnection ();
		Statement stmt;
		try {
			stmt = conn.createStatement();
		ResultSet rs = stmt.executeQuery(sqlQuery);
	
		System.out.println("{"+sqlQuery+"}");
		while (rs.next()) {
			
		   // System.out.print(rs.getRow() + ".|");
			
			for (int i = 1; i <= column; i++){
				System.out.print("\t" + rs.getString(i)+"\t"+"|");
			}
			System.out.println();
		}
		stmt.close();
		conn.close();
	
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 
	 * @param sqlQuery - SQL Query in the database 
	 * (SQL запрос на выборку данных из базы данных)
	 * @param column - Number of columns in table 
	 * (количество колонок в таблице)
	 * @return Table as Collection List of Strings, 
	 * where each row is an array of columns of cells
	 * (Коллекцию, как список строк, где каждая строка представляет 
	 * собой массив из столбцов ячеек)
	 */
	protected List<String[]> getTable(String sqlQuery, int column) {
		getConnection ();
		Statement stmt = null;
		ResultSet rs = null;
		try {
			stmt = conn.createStatement();
			rs = stmt.executeQuery(sqlQuery);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	
		List <String []> dataTable = new ArrayList<String []>();
		String [] row;
	
		try {
			while (rs.next()) {
				row = new String[column+1];
				for (int i = 1; i <= column; i++){
					row[i]=rs.getString(i);
				}
				dataTable.add(row);
			}
		stmt.close();
		conn.close();
	
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return dataTable;
	}
	
	/**
	 * @return Возвращает расширенный журнал в виде коллекции массивов
	 * <LI> дата
	 * <LI> название города
	 * <LI> период суток (утро, день, вечер, ночь)
	 * <LI> wind direction направление ветра (N, W, S, E, NE, NW...)
	 * <LI> site name имя сайта с прогнозом
	 * <LI> cloudiness облачность (%) 
	 * <LI> temperature температура (град.цельсия)
	 * <LI> precipitation осадки (мм)
	 * <LI> humidity влажность (%)
	 * <LI> pressure давление (мм.ртутного столба)
	 * <LI> windSpeed скорость ветра (м/с)
	  * <code></br></br>
	  * //Пример итерации этой коллекции
			</br>Database db = new Database();	  
			</br>List <String []> site = db.getSiteCity();
			</br>for (String[] s:site){
			</br>for (int i=1; i < site.get(1).length; i++){
			</br>System.out.print(s[i]+"\t| ");
			</br>}
			</br>System.out.println();
			</br>}</br>
	</code>
	 */
	public List<String[]> getJournal() {
		return getTable("SELECT * FROM linkJournal", 11);
	}
	
	/**
	 * @return Возвращается в виде массива:
	 * <LI> код города 
	 * <LI> название города
	 * <LI> http ссылка на сайте
	 * <LI> имя сайта
	 */
	public List<String[]> getSiteCity() {
		return getTable("SELECT * FROM siteCity", 4);
	}
	
	/**
	 * 
	 * @param siteName имя сайта gismeteo, pogodnik, 
	 * @return таблицу ссылок и гороов по переданному siteName
	 * <LI> код города 
	 * <LI> название города
	 * <LI> http ссылка на сайте
	 * <LI> имя сайта
	 */
	public List<String[]> getSiteCity(String siteName) {
		String sqlQuery = "SELECT * FROM siteCity WHERE (site_name='";
		sqlQuery=sqlQuery.concat(siteName).concat("')");
	return getTable(sqlQuery, 4);
	}
	
	/**
	 * Удаление строки из таблицы за указанную дату
	 * @param table имя таблицы
	 * @param journalDate дата в формате "2011-12-22"
	 * @return Возвращает количество удаленных строк
	 */
	private int deleteFromTable(String table, String journalDate) {
		getConnection();
		String sqlQuery="DELETE FROM "+ table + " WHERE (uptodate='" 
							+journalDate+"')";
		int delCount = 0;
		
		System.out.println("{"+sqlQuery+"}");
		
		Statement stmt;
		try {
			stmt = conn.createStatement();
			delCount = stmt.executeUpdate(sqlQuery);
		
		System.out.println("Delete: "+ delCount+" rows.");
		
		stmt.close();
		conn.close();
		
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return delCount;
	}
	
	/**
	 * Удаление строки из журнала погоды за указанную дату
	 * @param journalDate дата в формате "2011-12-22"
	 * @return Возвращает количество удаленных строк
	 */
	public int deleteFromJournal (String journalDate) {
		return deleteFromTable("journal", journalDate);
	}
	
	/**
	 * Удаление строки из журнала погоды за указанную дату
	 * @param journalDate дата в формате "2011-12-22"
	 * @return Возвращает количество удаленных строк
	 */
	public int deleteFromForecast (String journalDate) {
		return deleteFromTable("forecast", journalDate);
	}
	
	/**
	 * Удаляет записи из таблицы
	 * @param table имя таблицы
	 * @param journal_id код записи
	 * @return количество удаленных записей
	 */
	private int deleteFromTable (String table, int journal_id) {
		getConnection();
		String sqlQuery="DELETE FROM "+ table + 
				" WHERE (journal_id="+journal_id+")";
		int delCount = 0;
		
		System.out.println("{"+sqlQuery+"}");
	
		Statement stmt;
		try {
			stmt = conn.createStatement();
			delCount = stmt.executeUpdate(sqlQuery);
		
		System.out.println("Delete: "+ delCount+" rows.");
		
		stmt.close();
		conn.close();
		
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return delCount;
	}
	
	/**
	 * Удалет записи из журнала погоды
	 * @param journal_id код записи
	 * @return количество удаленных заисей
	 */
	public int deleteFromJournal (int journal_id){
		return deleteFromTable("journal", journal_id);
		
	}
	/**
	 * Удалет записи из журнала фактической погоды
	 * @param journal_id код записи
	 * @return количество удаленных заисей
	 */
	public int deleteFromForecast (int journal_id) {
		return deleteFromTable("forecast", journal_id);
		
	}
	/**
	 * Метод получает список городов из таблицы city базы данных
	 * @return возвращает коллекцию со списком городов
	 */
	public List<String> getListCity(){
		List<String> cityList = new ArrayList<String>();
		String sqlQuery = "SELECT city FROM city";
		System.out.println("SELECT city FROM city");
		getConnection ();
		Statement stmt = null;
		ResultSet rs = null;
		try {
			stmt = conn.createStatement();
			rs = stmt.executeQuery(sqlQuery);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		String row;
	
		try {
			while (rs.next()) {
					row = new String(rs.getString(1));
					cityList.add(row);
			}
			stmt.close();
			conn.close();
	
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return cityList;
	}
	/**
	 * Метод получает список дат в БД
	 * @return возвращает коллекцию со списком дат
	 */
	public List<String> getListDate(){
		List<String> dateList = new ArrayList<String>();
		String sqlQuery = "SELECT * FROM uptodate";
		System.out.println("SELECT * FROM uptodate");
		getConnection ();
		Statement stmt = null;
		ResultSet rs = null;
		try {
			stmt = conn.createStatement();
			rs = stmt.executeQuery(sqlQuery);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		String row;
	
		try {
			while (rs.next()) {
					row = new String(rs.getString(1));
					dateList.add(row);
			}
			stmt.close();
			conn.close();
	
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return dateList;
	}
}